/*
 * @Author: Colin Dai
 * @Date: 2022-05-17 14:05:57
 * @LastEditors: Colin Dai
 * @LastEditTime: 2022-05-18 21:47:43
 * @FilePath: \joystick\src\joystick\joystick.ino
 * @Description: 
 * dailianzheng@163.com
 * Copyright (c) 2022 by Colin.Dai, All Rights Reserved. 
 */

#include "USB.h"//调用USB库
#include "Mkeyin3.h"//按键函数库调用
#include "keys.h"

const int OFF_POW=0;//关机引脚


USBCDC USBSerial;//使用USB转串口功能
Mkeyin3 Mkey; //按键控制芯片设置



//========所有IO功能口定义===========

//--------无线模块------
const int M24G_RXD = 43;
const int M24G_TXD = 44;
const int M24G_SET = 41;
const int M24G_CS = 42;


//--------震动电机、蜂鸣器，LED灯，关机---------
const int voltPin = 5; //电压读取管脚
const int Motor_L= 36;
const int Motor_R = 39;
const int buzzer = 40;
const int POW_OFF = 0;
const int Tdao = 0;//通道定义
const int Rocker_LX = 3;//左摇杆水平
const int Rocker_LY = 4;//左摇杆垂直
const int Rocker_RX = 1;//右摇杆水平
const int Rocker_RY = 2;//右摇杆垂直
const int LED_B = 37;//绿色LED引脚
const int LED_G = 38;//蓝色LED引脚


//==============变量定义==================
unsigned int keyint=0;//测试电压摇杆标记变量
byte setwi;//无线模块设置状态变量
float Var;//计算公式得到的数值存储变量
float voltage;//电压计算值存储变量
float DianYa=0;//输出电压存储值
byte Lset;  //左摇杆数据发送状态变量
byte Rset;  //左摇杆数据发送状态变量
int L1int=0;  //左摇杆上下数据存储变量
int L2int=0;  //左摇杆左右数据存储变量
int R1int=0;  //右摇杆上下数据存储变量
int R2int=0;  //右摇杆左右数据存储变量
int YG_FW_MAX=675;//摇杆最大范围值
int YG_FW_MIN=640;//摇杆最小范围值


//=========== 标志=========================
boolean setWX= false;//false!true 切换串口转发功能标志，主要用于软件设置无线模块。
//==========================================


void setup() {

 //设置管脚输出
 pinMode(M24G_CS, OUTPUT);//设置为输出
 pinMode(M24G_SET, OUTPUT);//设置为输出
 pinMode(Motor_L, OUTPUT);//左震动电机
 pinMode(Motor_R, OUTPUT);//右震动电机
 pinMode(buzzer, OUTPUT);//蜂鸣器管脚设置为输出状态
 pinMode(LED_B, OUTPUT);//设定绿色LED引脚为输出模式
 pinMode(LED_G, OUTPUT);//设定蓝色LED引脚为输出模式
 
 
 USBSerial.begin();//初始化USB转串口
 USB.begin();//初始化USB
 Serial.begin(9600);//无线模块串口，波特率设置为9600
 Mkey.begin();//按键函数库初始化

 
 digitalWrite(M24G_CS, LOW);//设置无线模块开启（2.4G无线模块可用）
 digitalWrite(M24G_SET, HIGH);//设置无线模块管脚关闭
 digitalWrite(LED_B, HIGH);//运行指示绿色LED
 digitalWrite(LED_G, HIGH);//运行指示蓝色LED
 delay(200); //延时200ms                      
 digitalWrite(LED_B, LOW);//运行指示绿色LED
 digitalWrite(LED_G, LOW);//运行指示蓝色LED
 delay(200); //延时1000ms
 analogReadResolution(10);//ADC分辨率10位
}

void loop() {

  //无线模块正常，发出声音
  while (Serial.available() > 0) {
    if (Serial.read()=='A'){
      bibi();
      }
   }

 
 voltage =analogRead(voltPin);//读取电池接口的电压
 DianYa=(voltage*3.3)/(1023)*1.55;//将读到的电压转换成实际测量的电压值

//USBSerial.print("电压:");//串口输出“电压： ”字符
//USBSerial.println(DianYa);//串口输出电池电压数值，并且换行
if(DianYa <= 3.6){ //判断低于3.6V就关机（电池电压充满在4.2左右，正常低于3.6V就需要关机保护电池）
  lowpwer_bi();
  power_off();//关机
}

 
 int LX = analogRead(Rocker_LX);//读取左摇杆X轴
 int LY = analogRead(Rocker_LY);//读取左摇杆Y轴
 int RX = analogRead(Rocker_RX);//读取右摇杆X轴
 int RY = analogRead(Rocker_RY);//读取右摇杆Y轴
 L1int =YG_JZ(LX);//将摇杆的值转换成8位值方便传输
 L2int =YG_JZ(LY);//将摇杆的值转换成8位值方便传输 
 R1int =YG_JZ(RX);//将摇杆的值转换成8位值方便传输
 R2int =YG_JZ(RY);//将摇杆的值转换成8位值方便传输  

 //输出按键值
  if (Mkey.update()) {
    for (int i = 0; i < Mkey.getDataWidth(); i++);
   // Serial.println(shift.getCurrent());
   keyint=Mkey.getCurrent();   

   //通过无线发送
   TX_joystick_data(keyint,L1int,L2int,R1int,R2int);
     
   USBSerial.println(keyint);
  }  


 //======SELECT+START按键切换无线串口模块AT设置===============
  if(keyint == KEY_STAR_SELECT){
    setwi=!setwi;//设置标志位
    digitalWrite(LED_G, setwi);//功能指示灯开启用于显示无线模块开始设置
  }


  if(setwi==1){//如果是组合键按下则启动设置无线模块参数
    digitalWrite(M24G_SET, LOW);//启用无线模块设置模式
    if (Serial.available()) {      //如果无线模块有数据
       USBSerial.write(Serial.read());//读取无线模块数据从USB模拟串口输出
     }
     if (USBSerial.available()) {     //如果USB串口有数据
       Serial.write(USBSerial.read());//读取USB数据从串口无线模块输出
      }
   }else
   {
    digitalWrite(M24G_SET, HIGH);//关闭无线模块设置模式
   }
//==============================================================
//==========L2按键控制振动电机==================================
   if(keyint == KEY_L2){
       analogWrite(Motor_L,150);//左震动电机震动级数150（0-255）
      }
      else{
        analogWrite(Motor_L, 0);//左震动电机震动级数0，也就是停止震动（0-255）
      }  
//=================================================================
//==========R2按键控制振动电机==================================
   if(keyint == KEY_R2){
       analogWrite(Motor_R, 150);//右震动电机震动级数150（0-255）   
      }
      else{
        analogWrite(Motor_R, 0);//右震动电机震动级数0，也就是停止震动（0-255）
      }
//=================================================================
//==========L1按键控制蜂鸣器==================================
   if(keyint== KEY_L1){
       ledcAttachPin(buzzer,Tdao);//初始化蜂鸣器功能
       ledcWriteNote(Tdao,NOTE_B,4);//发出声音C
      }
      else{
        ledcDetachPin(buzzer);//清除发声引脚
      }
//=================================================================
//==========R1按键读取电压==================================
   if(keyint==KEY_R1){
      /*
      Serial.print("Volts: ");//串口输出“Volts: ”字符串
      Serial.print(DianYa);//串口输出电池电压数值
      Serial.print("LX: ");//串口输出“LX: ”字符串
      Serial.print(L1int);//串口输出左摇杆X轴数据
      Serial.print("LY: ");//串口输出“LY: ”字符串
      Serial.print(L2int);//串口输出左摇杆Y轴数据
      Serial.print("RX: ");//串口输出“RX: ”字符串
      Serial.print(R1int);////串口输出右摇杆X轴数据
      Serial.print("RY: ");//串口输出“RY: ”字符串
      Serial.println(R2int);////串口输出右摇杆Y轴数据，并换行  
      */
      
      USBSerial.print("Volts: ");//串口输出“Volts: ”字符串
      USBSerial.print(DianYa);//串口输出电池电压数值
      USBSerial.print("LX: ");//串口输出“LX: ”字符串
      USBSerial.print(L1int);//串口输出左摇杆X轴数据
      USBSerial.print("LY: ");//串口输出“LY: ”字符串
      USBSerial.print(L2int);//串口输出左摇杆Y轴数据
      USBSerial.print("RX: ");//串口输出“RX: ”字符串
      USBSerial.print(R1int);////串口输出右摇杆X轴数据
      USBSerial.print("RY: ");//串口输出“RY: ”字符串
      USBSerial.println(R2int);////串口输出右摇杆Y轴数据，并换行
      }
//=================================================================
  delay(10);
} 


/**
 * @brief 发出蜂鸣声
 * @return {*}
 */
void bibi(){
  ledcAttachPin(buzzer,Tdao);//初始化蜂鸣器功能
  ledcWriteNote(Tdao,NOTE_G,4);//发出声音G
  delay(300);//延时200ms
  ledcWriteNote(Tdao,NOTE_B,4);//发出声音B
  delay(300);//延时200ms
  ledcWriteNote(Tdao,NOTE_C,4);//发出声音C
  delay(300);//延时200ms
  ledcDetachPin(buzzer);//清除发声引脚
  }

void lowpwer_bi(){
  ledcAttachPin(buzzer,Tdao);//初始化蜂鸣器功能
  ledcWriteNote(Tdao,NOTE_C,4);
  delay(300);//延时200ms
  ledcWriteNote(Tdao,NOTE_B,4);
  delay(300);//延时200ms
  ledcWriteNote(Tdao,NOTE_G,4);
  delay(300);//延时200ms
  ledcDetachPin(buzzer);//清除发声引脚
  }



/**
 * @brief 摇杆居中校准函数
 * @param undefined
 * @return {*}
 */  
int YG_JZ(int Zhi){

 if(Zhi>YG_FW_MAX){//摇杆大于700说明向最大方向
  Zhi =map(Zhi,YG_FW_MAX,1023,127,255);//将大于700和最大的1024值，转换成127-255值（每个摇杆都有误差）
  Zhi =constrain(Zhi,127,255);//将转换的值设置成绝对值
 }
 else if(Zhi<YG_FW_MIN)//摇杆小于600说明向最小方向
 {
  Zhi =map(Zhi,YG_FW_MIN,10,126,0);//将小于600和最小到20的值，转换成162-0值（每个摇杆都有误差）
  Zhi =constrain(Zhi,0,126);//将转换的值设置成绝对值
 }
 else if(Zhi<YG_FW_MAX&&Zhi>YG_FW_MIN)//如果摇杆小于最大值，大于最小值，说明摇杆在中间
 {
  Zhi =127;//将默认中间值设置为127
 }
 return Zhi;//返回计算好的值
}


//====================发送数据函数=========================
 void TX_joystick_data(int keyint,int L1int,int L2int,int R1int,int R2int) 
 { 
  byte tx_data[8];
  tx_data[0] = 0xAA;//数据头码
  tx_data[1] = highByte(keyint);//按键高8位值
  tx_data[2] = lowByte(keyint);//按键低8位值
  tx_data[3] = L1int; //左摇杆上下  
  tx_data[4] = L2int;//左摇杆左右
  tx_data[5] = R1int;//右摇杆上下
  tx_data[6] = R2int;//右摇杆左右
  tx_data[7] = 0xBB;//数据尾码
  Serial.write(tx_data,8); //将8个十六进制发送给串口无线模块

  USBSerial.write(tx_data,8);
}

void power_off(){//关机函数
  for(int i;i<60;i++){//关机需要60个高低电平才可以
  digitalWrite(LED_G, HIGH);//关机脉冲指示LED，开
  digitalWrite(OFF_POW,HIGH);////关机高脉冲
  delay(5);//短延时10ms
  digitalWrite(LED_G, LOW);//关机脉冲指示LED，关
  digitalWrite(OFF_POW,LOW);//关机低脉冲
  delay(5);//短延时10ms
  }
}

